package com.wms.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wms.dao.SystemMapper;
import com.wms.domain.BasePageDomain;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.sql.Connection;
import java.util.*;

import static org.apache.ibatis.reflection.SystemMetaObject.DEFAULT_OBJECT_FACTORY;
import static org.apache.ibatis.reflection.SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY;
import static org.springframework.util.ObjectUtils.isEmpty;

//@Component
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class SqlInterceptorCount implements Interceptor {

    @Autowired
    private SystemMapper systemMapper;

    private static final Logger log = LoggerFactory.getLogger(SqlInterceptorCount.class);

    private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();
    @Override
    public Object intercept(Invocation invocation) throws Throwable {


        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        BoundSql boundSql = statementHandler.getBoundSql();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
//        HashMap mapParam = (HashMap) metaStatementHandler.getValue("delegate.boundSql.parameterObject");
//        log.info("111111111111111111xxxxx"+(String) metaStatementHandler.getValue("delegate.boundSql.sql"));
//        log.info("111111111111111111xxxxx2"+(String) metaStatementHandler.getValue("delegate.boundSql.parameterObject"));
//        JSONObject js = JSONObject.toJSONString(metaStatementHandler.getValue("delegate.boundSql.parameterObject"));

        String json = JSONObject.toJSONString(metaStatementHandler.getValue("delegate.boundSql.parameterObject"));
        String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
        if(!isEmpty(sql)){
            List<String> key = parseKey(sql);
            if(!key.isEmpty()){
                String sumSql = createSql(key);
                log.info("1111111"+sumSql);
            }
        }
        if(!isEmpty(json) && !"null".equals(json)  && json.contains(":") && !sql.contains("count(1)")){
            //处理sum

            HashMap hashMap = JSON.parseObject(json, HashMap.class);
//            BasePageDomain bpd =  (BasePageDomain) metaStatementHandler.getValue("delegate.boundSql.parameterObject");
            if(hashMap.get("sort") !=null && hashMap.get("sortType") !=null){
                if(!sql.contains("ORDER BY")){
                    log.info("before ORDER BY sql "+ sql);
                    int index = sql.indexOf("LIMIT");
                    if(index >=0){
                        StringBuilder sb = new StringBuilder(sql);
                        sb.insert(index," ORDER BY " + hashMap.get("sort") + " "+ hashMap.get("sortType")+" ");
                        sql = sb.toString();
                    }else{
                        sql = sql + " ORDER BY " + hashMap.get("sort") + " "+ hashMap.get("sortType")+" ";
                    }

                    log.info("alter ORDER BY sql "+ sql);
                    metaStatementHandler.setValue("delegate.boundSql.sql", sql);
                }
            }
            if(hashMap.get("maxResult") !=null && hashMap.get("startPosition") !=null){
                if(!sql.contains("LIMIT")){
//                    SQL_CALC_FOUND_ROWS
                    log.info("before sql "+ sql);
//                    int index = sql.indexOf("SELECT");
//                    StringBuilder sb = new StringBuilder(sql);
//                    sb.insert(index+6," SQL_CALC_FOUND_ROWS ");
//                    sql = sb.toString();
                    int index = sql.indexOf("FROM");
                    BasePageDomain bpd =  (BasePageDomain) metaStatementHandler.getValue("delegate.boundSql.parameterObject");
                    String newSql = sql.substring(index);




//                    bpd.setBaseCount(getTableCount(newSql));
                    metaStatementHandler.setValue("delegate.boundSql.parameterObject",bpd);
                    sql = sql + " LIMIT " + hashMap.get("startPosition") + " , "+hashMap.get("maxResult");
//                    sql = sql + " ;select FOUND_ROWS() as total";
                    log.info("alter sql "+ sql);

                    metaStatementHandler.setValue("delegate.boundSql.sql", sql);
                }
            }
        }

        // 继续执行拦截之前的操作
        return invocation.proceed();
    }


    public Long getTableCount(String sql){
//        log.info("asd123xxxxxxxxx"+sql);
        return (long) systemMapper.getTableCount(sql);
    }

    public boolean isSum(String key){
        return Config.table_key.containsKey(key);
    }

    public String createSql(List<String> keys){
        StringBuilder newSql = new StringBuilder("SELECT ");
        for (String key:keys){
            newSql.append(" SUM(").append(key).append("),");
        }
        newSql.deleteCharAt(newSql.length() - 1);
        newSql.append(" FROM ");
        return newSql.toString();
    }

    public List<String> parseKey(String sql){
        List<String> list = new ArrayList<String>();
        int begin = sql.indexOf("SELECT");
        int end = sql.indexOf("FROM");
        String keys = sql.substring(begin+6,end);
        if(isEmpty(keys)){
            return null;
        }
        StringTokenizer result = new StringTokenizer(keys,",");
        if(isEmpty(result)){
            return null;
        }
        while(result.hasMoreTokens()){ // 对 result 遍历并打印子字符串；
            String key = result.nextToken();
            if(isSum(key)){
                list.add(key);
            }
        }
        return list;
    }

    @Override
    public Object plugin(Object target) {
        /*
            根据Intercepts注解，拦截 StatementHandler 的prepare 方法
         */
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}